/*
 * generic.cpp
 *
 *  Created on: Mar 2, 2011
 *      Author: soapy
 */

#include "GenericConnection.h"

int SetupTCPClientSocket(const char *host, const char *service)
{

	//define the kind of address we want
	struct addrinfo addrCriteria;	//criteria for address match
	memset(&addrCriteria, 0, sizeof(addrCriteria));	//zero out addrCriteria
	addrCriteria.ai_family = AF_INET;
	addrCriteria.ai_socktype = SOCK_STREAM;
	addrCriteria.ai_protocol = IPPROTO_TCP;

	//get addresses
	/*TODO: Make sure this declare is right */
	struct addrinfo *servAddr;	//holds returned list of server addresses
	int rtnVal = getaddrinfo(host, service, &addrCriteria, &servAddr);
	if(rtnVal != 0)
	{
		printf("getaddrinfo() failure");
		exit(1);
	}

	int sock = -1;
	struct addrinfo *addr;
	for(addr = servAddr; addr != NULL; addr = addr->ai_next)
	{
		sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
		if(sock < 0)
		{
			continue;	//socket creation failed, try with next address
		}

		if(connect(sock, addr->ai_addr, addr->ai_addrlen) == 0)
		{
			break;	//socket connection success
		}

		close(sock);	//socket creation failed
	}

	freeaddrinfo(servAddr);
	return sock;
}

static const int MAXPENDING = 5;

int SetupTCPServerSocket(const char *service)
{
	//Construct server address structure
	struct addrinfo addrCriteria;
	memset(&addrCriteria, 0, sizeof(addrCriteria));
	addrCriteria.ai_family = AF_UNSPEC;
	addrCriteria.ai_flags = AI_PASSIVE;
	addrCriteria.ai_socktype = SOCK_STREAM;
	addrCriteria.ai_protocol = IPPROTO_TCP;

	struct addrinfo *servAddr;
	int rtnVal = getaddrinfo(NULL, service, &addrCriteria, &servAddr);
	if(rtnVal != 0)
	{
		printf("getaddrinfo() failure");
		exit(1);
	}

	int servSock = -1;
	struct addrinfo *addr;
	for(addr = servAddr; addr != NULL; addr = addr->ai_next)
	{
		servSock = socket(servAddr->ai_family, servAddr->ai_socktype,
				servAddr->ai_protocol);
		if(servSock < 0)
		{
			continue;	//socket creation failure, try next address
		}

		if((bind(servSock, servAddr->ai_addr, servAddr->ai_addrlen) == 0) &&
				(listen(servSock, MAXPENDING) == 0))
		{
			struct sockaddr_storage localAddr;
			socklen_t addrSize = sizeof(localAddr);
			if(getsockname(servSock, (struct sockaddr *) &localAddr, &addrSize) < 0)
			{
				printf("getsockname() failure");
				exit(1);
			}
			fputs("Binding to", stdout);
			PrintSocketAddress((struct sockaddr *) &localAddr, stdout);
			fputc('\n', stdout);
			break; //bind and list successful
		}

		close(servSock);
		servSock = -1;

	}

	freeaddrinfo(servAddr);

	return servSock;
}

int AcceptTCPConnection(int servSock)
{
	struct sockaddr_storage clntAddr; //Client address
	//Set length of client address structure (in-out parameter)
	socklen_t clntAddrLen = sizeof(clntAddr);

	//Wait for client
	int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);
	if(clntSock < 0)
	{
		printf("accept() failure");
		exit(1);
	}

	//clntSock is connected

	fputs("Handling client", stdout);
	PrintSocketAddress((struct sockaddr *) &clntAddr, stdout);
	fputc('\n', stdout);

	return clntSock;
}
